using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;

using InfFront.UICore;

namespace InfFront.InfoViews.Base
{
    internal class InfoViewEntries : IBindingListView, IBindingList, IList, ICollection, IEnumerable, ITypedList, ICancelAddNew, ISupportInitializeNotification, ISupportInitialize, IDisposable
    {
        #region Private Variables
        private InfoViewSource owner;
        private IInfoEntries entries;
        private bool endingEdit;
        private bool initializing;
        private int lastIndex = -1;
        private InfoViewRecord lastEntry = null;
        private EventHandlerList events;
        private InfoSourceGetEntriesArgs args;

        private static readonly object EVENT_INITIALIZED = new object();
        private static readonly object EVENT_LISTCHANGED = new object();
        #endregion

        public InfoViewEntries(InfoViewSource owner)
        {
            this.owner = owner;
            args = new InfoSourceGetEntriesArgs();
            this.events = new EventHandlerList();
        }

        internal InfoViewSource Owner
        {
            get { return owner; }
        }

        private IInfoEntries List
        {
            get
            {
                if (entries == null)
                    entries = owner.GetNewEntries(args);
                return entries;
            }
        }

        // Fields

        // Events

        public event ListChangedEventHandler ListChanged
        {
            add { events.AddHandler(EVENT_LISTCHANGED, value); }
            remove { events.RemoveHandler(EVENT_LISTCHANGED, value); }
        }

        event EventHandler ISupportInitializeNotification.Initialized
        {
            add { events.AddHandler(EVENT_INITIALIZED, value); }
            remove { events.RemoveHandler(EVENT_INITIALIZED, value); }
        }

        // Methods
        public virtual object AddNew()
        {
            //if (!this.AllowNewInternal(false))
            //{
            //    throw new InvalidOperationException(SR.GetString("BindingSourceBindingListWrapperAddToReadOnlyList"));
            //}
            //if (!this.AllowNewInternal(true))
            //{
            //    throw new InvalidOperationException(SR.GetString("BindingSourceBindingListWrapperNeedToSetAllowNew", new object[] { (this.itemType == null) ? "(null)" : this.itemType.FullName }));
            //}
            //int addNewPos = this.addNewPos;
            //this.EndEdit();
            //if (addNewPos != -1)
            //{
            //    this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, addNewPos));
            //}
            //AddingNewEventArgs e = new AddingNewEventArgs();
            //int count = this.List.Count;
            //this.OnAddingNew(e);
            //object newObject = e.NewObject;
            //if (newObject == null)
            //{
            //    if (this.isBindingList)
            //    {
            //        newObject = (this.List as IBindingList).AddNew();
            //        this.Position = this.Count - 1;
            //        return newObject;
            //    }
            //    if (this.itemConstructor == null)
            //    {
            //        throw new InvalidOperationException(SR.GetString("BindingSourceBindingListWrapperNeedAParameterlessConstructor", new object[] { (this.itemType == null) ? "(null)" : this.itemType.FullName }));
            //    }
            //    newObject = this.itemConstructor.Invoke(null);
            //}
            //if (this.List.Count > count)
            //{
            //    this.addNewPos = this.Position;
            //    return newObject;
            //}
            //this.addNewPos = this.Add(newObject);
            //this.Position = this.addNewPos;
            //return newObject;
            return null;
        }

        private void FireListChanged()
        {
            if (events == null)
                return;
            var handler = (ListChangedEventHandler)events[EVENT_LISTCHANGED];
            if (handler != null)
            {
                var args = new ListChangedEventArgs(ListChangedType.Reset, null);
                handler(this, args);
            }
        }

        public virtual void ApplySort(ListSortDescriptionCollection sorts)
        {
            args.Sortings.Clear();
            foreach (ListSortDescription sort in sorts)
            {
                args.Sortings.Add(new InfoSourceGetEntriesArgs.SortDescription() 
                    { FieldName = sort.PropertyDescriptor.Name,
                      Direction = sort.SortDirection });
            }
            entries = null;
            FireListChanged();
        }

        public virtual void ApplySort(PropertyDescriptor property, ListSortDirection sort)
        {
            var col = new ListSortDescriptionCollection(
                new ListSortDescription[] { new ListSortDescription(property, sort)});
            ApplySort(col);
        }

        public virtual void Clear()
        {
            Debug.Assert(false);
        }

        public virtual bool Contains(object value)
        {
            var rec = (InfoViewRecord)value;
            return List.IndexOf(rec.Origin) >= 0;
        }

        public virtual void CopyTo(Array arr, int index)
        {
            foreach (var item in this)
            {
                arr.SetValue(item, index++);
            }
        }

        public virtual void Dispose()
        {
            if (lastEntry != null)
            {
                if (!lastEntry.IsDisposed)
                    lastEntry.Dispose();
                lastEntry = null;
            }
        }

        public void EndEdit()
        {
            if (!this.endingEdit)
            {
                try
                {
                    this.endingEdit = true;
                }
                finally
                {
                    this.endingEdit = false;
                }
            }
        }

        private void EndInitCore()
        {
            this.initializing = false;
            this.OnInitialized();
        }

        public virtual int Find(PropertyDescriptor prop, object key)
        {
            Debug.Assert(false);
            return 0;
        }

        public int Find(string propertyName, object key)
        {
            Debug.Assert(false);
            return 0;
        }

        public virtual IEnumerator GetEnumerator()
        {
            foreach (var val in List)
            {
                yield return owner.WrapEntry(val);
            }
        }

        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
        {
            Debug.Assert(listAccessors == null);
            return Owner.GetRecordProperties();
        }

        public virtual string GetListName(PropertyDescriptor[] listAccessors)
        {
            return owner.Name;
        }

        public virtual int IndexOf(object value)
        {
            return List.IndexOf(((InfoViewRecord) value).Origin);
        }

        public virtual void Insert(int index, object value)
        {
            Debug.Assert(false);
        }

        private void OnInitialized()
        {
            EventHandler handler = (EventHandler) events[EVENT_INITIALIZED];
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        public virtual int Add(object value)
        {
            Debug.Assert(false);
            return 0;
        }

        public virtual void Remove(object value)
        {
            Debug.Assert(false);
        }

        public virtual void RemoveAt(int index)
        {
            Debug.Assert(false);
        }

        public virtual void RemoveFilter()
        {
            //this.filter = null;
            //IBindingListView list = this.List as IBindingListView;
            //if (list != null)
            //{
            //    list.RemoveFilter();
            //}
        }

        public virtual void RemoveSort()
        {
            args.Sortings.Clear();
        }

        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public virtual void ResetAllowNew()
        {
        }

        public void ResetBindings(bool metadataChanged)
        {
            //if (metadataChanged)
            //{
            //    this.OnListChanged(new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, null));
            //}
            //this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

        //public void ResetItem(int itemIndex)
        //{
        //    //this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, itemIndex));
        //}

        void IBindingList.AddIndex(PropertyDescriptor property)
        {
            Debug.Assert(false);
        }

        void IBindingList.RemoveIndex(PropertyDescriptor prop)
        {
            Debug.Assert(false);
        }

        void ICancelAddNew.CancelNew(int position)
        {
            //if ((this.addNewPos >= 0) && (this.addNewPos == position))
            //{
            //    this.RemoveAt(this.addNewPos);
            //    this.addNewPos = -1;
            //}
        }

        void ICancelAddNew.EndNew(int position)
        {
            //if ((this.addNewPos >= 0) && (this.addNewPos == position))
            //{
            //    this.addNewPos = -1;
            //}
        }

        void ISupportInitialize.BeginInit()
        {
            this.initializing = true;
        }

        void ISupportInitialize.EndInit()
        {
            this.EndInitCore();
        }

        // Properties
        public virtual bool AllowEdit
        {
            get { return false; }
        }

        public virtual bool AllowNew
        {
            get { return false; }
            set
            {
                Debug.Assert(!value);
            }
        }

        public virtual bool AllowRemove
        {
            get { return false; }
        }

        public virtual int Count
        {
            get { return List.GetCount(); }
        }

        public bool IsBindingSuspended
        {
            get { return false; }
        }

        public virtual bool IsFixedSize
        {
            get { return false; }
        }

        public virtual bool IsReadOnly
        {
            get { return true; }
        }

        public virtual bool IsSorted
        {
            get { return args.Sortings.Count > 0; }
        }

        public virtual bool IsSynchronized
        {
            get { return true; }
        }

        public virtual object this[int index]
        {
            get
            {
                if (index != lastIndex)
                {
                    lastIndex = index;
                    lastEntry = owner.WrapEntry(List.GetItem(index));
                }
                return lastEntry;
            }
            set
            {
                throw new NotSupportedException("BindingSource doesn't support indexed item replace");
            }
        }

        public virtual ListSortDescriptionCollection SortDescriptions
        {
            get 
            {
                if (args.HasSortings)
                {
                    var result = new ListSortDescription[args.Sortings.Count];
                    var props = Owner.GetRecordProperties();
                    for (int i = 0; i < args.Sortings.Count; ++i)
                    {
                        var sort = args.Sortings[i];
                        result[i] = new ListSortDescription(props[sort.FieldName], sort.Direction);
                    }
                    return new ListSortDescriptionCollection(result);
                }
                return null; 
            }
        }

        public virtual object SyncRoot
        {
            get { return this; }
        }

        public virtual ListSortDirection SortDirection
        {
            get 
            {
                if (args.HasSortings)
                    return args.Sortings[0].Direction;
                return ListSortDirection.Ascending; 
            }
        }

        public virtual PropertyDescriptor SortProperty
        {
            get
            {
                if (args.HasSortings)
                {
                    var props = Owner.GetRecordProperties();
                    return props[args.Sortings[0].FieldName];
                }
                return null;
            }
        }

        public virtual bool SupportsAdvancedSorting
        {
            get { return Owner.SupportsSorting; }
        }

        public virtual bool SupportsChangeNotification
        {
            get { return true; }
        }

        public virtual bool SupportsFiltering
        {
            get { return false; }
        }

        public virtual string Filter
        {
            get
            {
                Debug.Assert(false);
                return null;
            }
            set
            {
                Debug.Assert(false);
            }
        }

        public bool SupportsSearching
        {
            get { return false; }
        }

        public virtual bool SupportsSorting
        {
            get { return Owner.SupportsSorting; }
        }

        bool ISupportInitializeNotification.IsInitialized
        {
            get { return !this.initializing; }
        }
    }
}
